var gewFrustumCheckOrder = [  [0,1,2,3,4,5] ,
                    [1,0,2,3,4,5] ,
                    [2,0,1,3,4,5] ,
                    [3,0,1,2,4,5] ,
                    [4,0,1,2,3,5] ,
                    [5,0,1,2,3,4] ]; // left 0 right 1 near 2 far 3 top 4 bottom 5
function gewFrustum()
{
  this.plane = [];
  for(var i=0;i<6;i++)
    this.plane[i] = new gewPlane();
  this.bitField = [];
  // Private:
  this.cacheLut = []  // Lookup table for this frustum
  for(var i=0;i<8;i++)
      this.cacheLut[i] = []; 
  //this.aabb = null // frustum's aabb, use to speed up culling again quadtree
}
gewFrustum.prototype = {
  isContainAabb: function(box)
  {
    // Create Look up table   
    var lut = this.cacheLut; 
    var max = box.max;
    var min = box.min;
    var maxx = max.x;
    var maxy = max.y;
    var maxz = max.z;
    var minx = min.x;
    var miny = min.y;
    var minz = min.z;
    // bitField = 000 -> x = x_min, y = y_min , z = z_min
    lut[0][0] = minx;
    lut[0][1] = miny;
    lut[0][2] = minz;
    // bitField = 001 -> x = x_min, y = y_min , z = z_max
    lut[1][0] = minx;
    lut[1][1] = miny;
    lut[1][2] = maxz;
    // bitField = 010 -> x = x_min, y = y_max , z = z_min
    lut[2][0] = minx;
    lut[2][1] = maxy;
    lut[2][2] = minz;
    // bitField = 011 -> x = x_min, y = y_max , z = y_max
    lut[3][0] = minx;
    lut[3][1] = maxy;
    lut[3][2] = maxz;
    // bitField = 100 -> x = x_max, y = y_min , z = z_min
    lut[4][0] = maxx;
    lut[4][1] = miny;
    lut[4][2] = minz;
    // bitField = 101 -> x = x_max, y = y_min , z = z_max
    lut[5][0] = maxx;
    lut[5][1] = miny;
    lut[5][2] = maxz;
    // bitField = 110 -> x = x_max, y = y_max , z = z_min
    lut[6][0] = maxx;
    lut[6][1] = maxy;
    lut[6][2] = minz;
    // bitField = 111 -> x = x_max, y = y_max , z = y_max
    lut[7][0] = maxx;
    lut[7][1] = maxy;
    lut[7][2] = maxz;
    var intersect = false;
    var outerPlane = box.outerPlane;
    var bitField = this.bitField;
    var plane = this.plane;
    for(var j = 0; j < 6; ++j) 
    {
      var i = gewFrustumCheckOrder[ outerPlane ][j];
      var bf = bitField[i];
      // gewRegVec0 is a box conner that have greatest SIGNED distance from plane i
      gewRegVec0.set( lut[ bf ][0], lut[ bf ][1], lut[ bf ][2]);    
      var invert_bf = (~bf)& 0x7;
      // gewRegVec1 is a box conner that have smallest SIGNED distance from plane i
      gewRegVec1.set( lut[ invert_bf ][0],lut[ invert_bf ][1],lut[ invert_bf ][2] );
      if( plane[i].distanceToPoint(gewRegVec0) <0)
      {
        box.outerPlane = i;
        return GEW_OUT;
      }
      if( plane[i].distanceToPoint(gewRegVec1) <0)
        intersect = true;           
    }
    if( intersect ) 
      return GEW_INTERSECT;
    return GEW_IN;
  },
  isContainSphere: function(sphere)
  {
    var fDistance;
    var outerPlane = sphere.outerPlane;
    var plane = this.plane;
    for(var j = 0; j < 6; ++j) 
    {   
      var i = gewFrustumCheckOrder[ outerPlane ][ j ];
      // calculate distances from center to this plane
      fDistance = plane[i].distanceToPoint(sphere.center);
      // if this distance is < -sphere.radius, the sphere's outside
      if(fDistance < -sphere.radius)
      {
        sphere.outerPlane = i;
        return GEW_OUT;
      }
      // else if the distance is between +- radius, then we intersect
      if( Math.abs(fDistance) < sphere.radius)
        return GEW_INTERSECT;
    }            
    return GEW_IN;
  }
}